#pragma once
#include"util.hpp"
enum ss_statu{UNLOGIN,LOGIN};
class Session
{
    private:
    uint64_t _ssid;//标识符
    uint64_t _uid;//对应的用户id
    ss_statu _staus;//用户登陆状态
    websocket_server::timer_ptr _tp;//session相关定时器
    public:
    Session(uint64_t ssid):_ssid(ssid){DEBUG_LOG("session:%lu被创建!",_ssid);}
    ~Session(){DEBUG_LOG("session:%lu被释放!",_ssid);}
    void set_statu(ss_statu statu){_staus=statu;};
    void set_user(uint64_t uid){_uid=uid;}
    uint64_t get_user(){return _uid;}
    uint64_t get_ssid(){return _ssid;}
    bool is_login(){return _staus==LOGIN;}
    void set_timer(const websocket_server::timer_ptr& tp){_tp=tp;}
    websocket_server::timer_ptr get_timer(){return _tp;}
};

using session_ptr=std::shared_ptr<Session>;
#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
class session_manager
{
    private:
    std::mutex _mutex;
    std::unordered_map<uint64_t,session_ptr> _session;//ssid与session的映射关系
    websocket_server* _server;
    uint64_t _next_ssid;
    public:
    session_manager(websocket_server* server):_server(server),_next_ssid(1){DEBUG_LOG("session管理器创建成功");}
    ~session_manager(){DEBUG_LOG("session管理器释放成功");}
    session_ptr create_session(uint64_t uid,ss_statu statu)
    {
        std::unique_lock<std::mutex> _guard;
        session_ptr ss_ptr=std::make_shared<Session>(_next_ssid);
        ss_ptr->set_user(uid);
        ss_ptr->set_statu(statu);
        _session[_next_ssid]=ss_ptr;
        ++_next_ssid;
        return ss_ptr;
    }
    session_ptr get_session_by_ssid(uint64_t ssid)
    {
        std::unique_lock<std::mutex> _guard;
        auto it=_session.find(ssid);
        if(it==_session.end())
            return session_ptr();
        return it->second;
    }
    void append_session(const session_ptr& ss)
    {
        std::unique_lock<std::mutex> _guard;
        _session[ss->get_ssid()]=ss;
    }
    void set_session_expire_time(uint64_t ssid,int ms)
    {
        //依赖于websocketpp定时器实现session生命周期管理
        //在http通信时（登录、注册），应该具备生命周期，指定时间后无通信要删除
        //在websocket长连接通信时，session应该永久存在
        //登录之后创建session，指定时间后无通信要删除
        //进入游戏大厅或房间，session应该永久存在
        //退出游戏大厅或房间。指定时间后无通信要删除
        session_ptr ss_ptr=get_session_by_ssid(ssid);
        if(ss_ptr.get()==nullptr)
            return;
        websocket_server::timer_ptr tp=ss_ptr->get_timer();
        //1.在session永久存在的情况下设置永久存在
        if(tp.get()==nullptr&&ms==SESSION_FOREVER)
            return;
        else if(tp.get()==nullptr&&ms!=SESSION_FOREVER)
        {
            //2.在session永久存在的情况下设置指定时间之后的被删除的定时任务
            websocket_server::timer_ptr tm_ptr=_server->set_timer(ms,
            std::bind(&session_manager::remove_session,this,ssid));
            ss_ptr->set_timer(tm_ptr);
        }
        else if(tp.get()!=nullptr&&ms==SESSION_FOREVER)
        {
            //3.在设置了定时删除的情况下，将session设置为永久存在
            //删除定时任务->导致定时事件直接被执行
            {
                //std::unique_lock<std::mutex> _guard;
                //重新再添加一次，由于是shared_ptr，前面保存了一份，所以资源此时还没有被删除
                tp->cancel();//这个操作是个异步操作，并不会立即取消
                //_session.insert({ssid,ss_ptr});//不能立即添加
                ss_ptr->set_timer(websocket_server::timer_ptr());//因为是取消，所以设置为空即可
                _server->set_timer(0,std::bind(&session_manager::append_session,this,ss_ptr));
            }
        }
        else if(tp.get()!=nullptr&&ms!=SESSION_FOREVER)
        {
            //4.在session设置了定时删除的情况下，将session重置删除时间
            tp->cancel();//这个操作是个异步操作，并不会立即取消,移除源定时器
            _server->set_timer(0,std::bind(&session_manager::append_session,this,ss_ptr));//增加session
            //_session.insert({ssid,ss_ptr});//不能立即添加
            websocket_server::timer_ptr tm_ptr=_server->set_timer(ms,std::bind(&session_manager::remove_session,this,ssid));
            //重新设置session相关定时器
            ss_ptr->set_timer(tm_ptr);//设置现定时器
        }
    }
    void remove_session(uint64_t ssid)
    {
        std::unique_lock<std::mutex> _guard;
        _session.erase(ssid);
    }
};